#include <linux/errno.h>
#include <linux/irq.h>

void (*handle_arch_irq)(struct pt_regs *);

void handle_bad_irq(struct irq_desc *desc)
{
	// unsigned int irq = irq_desc_get_irq(desc);

	printf("this is %s(): %d\r\n", __func__, __LINE__);

	// print_irq_desc(irq, desc);
	// kstat_incr_irqs_this_cpu(desc);
	// ack_bad_irq(irq);
}

irqreturn_t __handle_irq_event_percpu(struct irq_desc *desc, unsigned int *flags)
{
	irqreturn_t retval = IRQ_NONE;
	unsigned int irq = desc->irq_data.irq;
	struct irqaction *action;

	// printf("this is %s(): %d  irq = %d\r\n", __func__, __LINE__, irq);

	// record_irq_time(desc);

	for_each_action_of_desc(desc, action) {
		// printf("this is %s(): %d  irq = %d\r\n", __func__, __LINE__, irq);
		irqreturn_t res;

		/*
		 * If this IRQ would be threaded under force_irqthreads, mark it so.
		 */
		// if (irq_settings_can_thread(desc) &&
		//     !(action->flags & (IRQF_NO_THREAD | IRQF_PERCPU | IRQF_ONESHOT)))
		// 	lockdep_hardirq_threaded();

		// trace_irq_handler_entry(irq, action);
		res = action->handler(irq, action->dev_id);
		// trace_irq_handler_exit(irq, action, res);

		// if (WARN_ONCE(!irqs_disabled(),"irq %u handler %pS enabled interrupts\n",
		// 	      irq, action->handler))
		// 	local_irq_disable();

		// switch (res) {
		// case IRQ_WAKE_THREAD:
		// 	/*
		// 	 * Catch drivers which return WAKE_THREAD but
		// 	 * did not set up a thread function
		// 	 */
		// 	if (unlikely(!action->thread_fn)) {
		// 		warn_no_thread(irq, action);
		// 		break;
		// 	}

		// 	__irq_wake_thread(desc, action);

		// 	fallthrough;	/* to add to randomness */
		// case IRQ_HANDLED:
		// 	*flags |= action->flags;
		// 	break;

		// default:
		// 	break;
		// }

		retval |= res;
	}

	return retval;
}

irqreturn_t handle_irq_event_percpu(struct irq_desc *desc)
{
	irqreturn_t retval;
	unsigned int flags = 0;

	// printf("this is %s(): %d\r\n", __func__, __LINE__);

	retval = __handle_irq_event_percpu(desc, &flags);

	// add_interrupt_randomness(desc->irq_data.irq, flags);

	// if (!irq_settings_no_debug(desc))
		// note_interrupt(desc, retval);
	return retval;
}

irqreturn_t handle_irq_event(struct irq_desc *desc)
{
	irqreturn_t ret;

	// printf("this is %s(): %d\r\n", __func__, __LINE__);

	// desc->istate &= ~IRQS_PENDING;
	// irqd_set(&desc->irq_data, IRQD_IRQ_INPROGRESS);
	// raw_spin_unlock(&desc->lock);

	ret = handle_irq_event_percpu(desc);

	// raw_spin_lock(&desc->lock);
	// irqd_clear(&desc->irq_data, IRQD_IRQ_INPROGRESS);
	return ret;
}

int set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
	if (handle_arch_irq)
		return -EBUSY;

	handle_arch_irq = handle_irq;
	return 0;
}
